# 进程上下文切换
# void os_proc_ctx_switch(void);
# 将当前上下文保存在老上下文中,从新上下文中加载寄存器新值

.globl os_proc_ctx_switch
os_proc_ctx_switch:
    # 保存当前进程上下文
    addi sp, sp, -256
    sd ra, 0(sp)
    sd sp, 8(sp)
    sd gp, 16(sp)
    sd tp, 24(sp)
    sd t0, 32(sp)
    sd t1, 40(sp)
    sd t2, 48(sp)
    sd s0, 56(sp)
    sd s1, 64(sp)
    sd a0, 72(sp)
    sd a1, 80(sp)
    sd a2, 88(sp)
    sd a3, 96(sp)
    sd a4, 104(sp)
    sd a5, 112(sp)
    sd a6, 120(sp)
    sd a7, 128(sp)
    sd s2, 136(sp)
    sd s3, 144(sp)
    sd s4, 152(sp)
    sd s5, 160(sp)
    sd s6, 168(sp)
    sd s7, 176(sp)
    sd s8, 184(sp)
    sd s9, 192(sp)
    sd s10, 200(sp)
    sd s11, 208(sp)
    sd t3, 216(sp)
    sd t4, 224(sp)
    sd t5, 232(sp)
    sd t6, 240(sp)

    # 保存返回地址
    sd ra, 248(sp)

    # 记录当前进程内核栈地址到进程的kstack成员中
    la a0, proc_current  # a0 = &proc_current
    ld a1, 0(a0)         # a1 = proc_current
    sd sp, 0(a1)         # proc_current->kstack = sp;

    # 修改当前进程为新进程控制块地址
    la a0, proc_current  # a0 = &proc_current
    la a1, proc_ready    # a1 = &proc_ready
    ld a2, 0(a1)         # a2 = proc_ready
    sd a2, 0(a0)         # proc_current = a2

    # 获取新进程内核栈地址,其中保存了进程的上下文
    ld a1, 0(a0)        # a1 = proc_current
    ld sp, 0(a1)        # sp = proc_current->kstack;

    # 恢复返回地址
    ld a0, 248(sp)
    csrw sepc, a0

    # 恢复新进程上下文
    ld ra, 0(sp)
    ld sp, 8(sp)
    ld gp, 16(sp)
    ld tp, 24(sp)
    ld t0, 32(sp)
    ld t1, 40(sp)
    ld t2, 48(sp)
    ld s0, 56(sp)
    ld s1, 64(sp)
    ld a0, 72(sp)
    ld a1, 80(sp)
    ld a2, 88(sp)
    ld a3, 96(sp)
    ld a4, 104(sp)
    ld a5, 112(sp)
    ld a6, 120(sp)
    ld a7, 128(sp)
    ld s2, 136(sp)
    ld s3, 144(sp)
    ld s4, 152(sp)
    ld s5, 160(sp)
    ld s6, 168(sp)
    ld s7, 176(sp)
    ld s8, 184(sp)
    ld s9, 192(sp)
    ld s10, 200(sp)
    ld s11, 208(sp)
    ld t3, 216(sp)
    ld t4, 224(sp)
    ld t5, 232(sp)
    ld t6, 240(sp)
    addi sp, sp, 256
    
    sret

# 进程上下文切换,中断中使用,中断需要关闭状态
# void os_proc_int_ctx_sw(void);
# 从栈中恢复寄存器值
.globl os_proc_int_ctx_sw
os_proc_int_ctx_sw:
    # 修改当前进程为新进程控制块地址
    la a0, proc_current  # a0 = &proc_current
    la a1, proc_ready    # a1 = &proc_ready
    ld a2, 0(a1)         # a2 = proc_ready
    sd a2, 0(a0)         # proc_current = a2

    # 获取新进程内核栈地址,其中保存了进程被中断时的上下文
    ld a1, 0(a0)        # a1 = proc_current
    ld sp, 0(a1)        # sp = proc_current->kstack;

    # 恢复中断返回地址
    ld a0, 248(sp)
    csrw sepc, a0

    # 恢复新进程上下文
    ld ra, 0(sp)
    ld sp, 8(sp)
    ld gp, 16(sp)
    ld tp, 24(sp)
    ld t0, 32(sp)
    ld t1, 40(sp)
    ld t2, 48(sp)
    ld s0, 56(sp)
    ld s1, 64(sp)
    ld a0, 72(sp)
    ld a1, 80(sp)
    ld a2, 88(sp)
    ld a3, 96(sp)
    ld a4, 104(sp)
    ld a5, 112(sp)
    ld a6, 120(sp)
    ld a7, 128(sp)
    ld s2, 136(sp)
    ld s3, 144(sp)
    ld s4, 152(sp)
    ld s5, 160(sp)
    ld s6, 168(sp)
    ld s7, 176(sp)
    ld s8, 184(sp)
    ld s9, 192(sp)
    ld s10, 200(sp)
    ld s11, 208(sp)
    ld t3, 216(sp)
    ld t4, 224(sp)
    ld t5, 232(sp)
    ld t6, 240(sp)
    addi sp, sp, 256

    sret
